From 9d301d6e9ea60e94e62aa1bb2ab4c8300b750f4b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Sat, 12 Sep 2015 23:32:35 +0200 Subject: [PATCH] Use docopt's new syntax for repeatable options --- src/bin/bench.rs | 34 +++++------ src/bin/build.rs | 34 +++++------ src/bin/doc.rs | 28 ++++----- src/bin/rustc.rs | 34 +++++------ src/bin/test.rs | 38 ++++++------ src/cargo/ops/cargo_rustc/mod.rs | 3 +- src/cargo/ops/cargo_test.rs | 99 +++++++++++--------------------- tests/support/mod.rs | 47 ++++++++++++++- tests/test_cargo_bench.rs | 85 +++++++++++++++++++++++++++ tests/test_cargo_compile.rs | 6 +- tests/test_cargo_rustc.rs | 69 +++++++++++++++++++++- 11 files changed, 321 insertions(+), 156 deletions(-) diff --git a/src/bin/bench.rs b/src/bin/bench.rs index 47150dfab..7e658997d 100644 --- a/src/bin/bench.rs +++ b/src/bin/bench.rs @@ -26,25 +26,25 @@ pub const USAGE: &'static str = " Execute all benchmarks of a local package Usage: - cargo bench [options] [-p SPEC --package SPEC]... [--] [...] + cargo bench [options] [--] [...] Options: - -h, --help Print this message - --lib Benchmark only this package's library - --bin NAME Benchmark only the specified binary - --example NAME Benchmark only the specified example - --test NAME Benchmark only the specified test target - --bench NAME Benchmark only the specified bench target - --no-run Compile, but don't run benchmarks - -p SPEC, --package SPEC Package to run benchmarks for - -j N, --jobs N The number of jobs to run in parallel - --features FEATURES Space-separated list of features to also build - --no-default-features Do not build the `default` feature - --target TRIPLE Build for the target triple - --manifest-path PATH Path to the manifest to build benchmarks for - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never + -h, --help Print this message + --lib Benchmark only this package's library + --bin NAME Benchmark only the specified binary + --example NAME Benchmark only the specified example + --test NAME Benchmark only the specified test target + --bench NAME Benchmark only the specified bench target + --no-run Compile, but don't run benchmarks + -p SPEC, --package SPEC ... Package to run benchmarks for + -j N, --jobs N The number of jobs to run in parallel + --features FEATURES Space-separated list of features to also build + --no-default-features Do not build the `default` feature + --target TRIPLE Build for the target triple + --manifest-path PATH Path to the manifest to build benchmarks for + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never All of the trailing arguments are passed to the benchmark binaries generated for filtering benchmarks and generally providing options configuring how they diff --git a/src/bin/build.rs b/src/bin/build.rs index 6140ca961..27bcf57b1 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -28,25 +28,25 @@ pub const USAGE: &'static str = " Compile a local package and all of its dependencies Usage: - cargo build [options] [-p SPEC --package SPEC]... + cargo build [options] Options: - -h, --help Print this message - -p SPEC, --package SPEC Package to build - -j N, --jobs N The number of jobs to run in parallel - --lib Build only this package's library - --bin NAME Build only the specified binary - --example NAME Build only the specified example - --test NAME Build only the specified test target - --bench NAME Build only the specified benchmark target - --release Build artifacts in release mode, with optimizations - --features FEATURES Space-separated list of features to also build - --no-default-features Do not build the `default` feature - --target TRIPLE Build for the target triple - --manifest-path PATH Path to the manifest to compile - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never + -h, --help Print this message + -p SPEC, --package SPEC ... Package to build + -j N, --jobs N The number of jobs to run in parallel + --lib Build only this package's library + --bin NAME Build only the specified binary + --example NAME Build only the specified example + --test NAME Build only the specified test target + --bench NAME Build only the specified benchmark target + --release Build artifacts in release mode, with optimizations + --features FEATURES Space-separated list of features to also build + --no-default-features Do not build the `default` feature + --target TRIPLE Build for the target triple + --manifest-path PATH Path to the manifest to compile + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never If the --package argument is given, then SPEC is a package id specification which indicates which package should be built. If it is not given, then the diff --git a/src/bin/doc.rs b/src/bin/doc.rs index 8bc6289b5..16fd12430 100644 --- a/src/bin/doc.rs +++ b/src/bin/doc.rs @@ -22,22 +22,22 @@ pub const USAGE: &'static str = " Build a package's documentation Usage: - cargo doc [options] [-p SPEC --package SPEC]... + cargo doc [options] Options: - -h, --help Print this message - --open Opens the docs in a browser after the operation - -p SPEC, --package SPEC Package to document - --no-deps Don't build documentation for dependencies - -j N, --jobs N The number of jobs to run in parallel - --release Build artifacts in release mode, with optimizations - --features FEATURES Space-separated list of features to also build - --no-default-features Do not build the `default` feature - --target TRIPLE Build for the target triple - --manifest-path PATH Path to the manifest to document - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never + -h, --help Print this message + --open Opens the docs in a browser after the operation + -p SPEC, --package SPEC ... Package to document + --no-deps Don't build documentation for dependencies + -j N, --jobs N The number of jobs to run in parallel + --release Build artifacts in release mode, with optimizations + --features FEATURES Space-separated list of features to also build + --no-default-features Do not build the `default` feature + --target TRIPLE Build for the target triple + --manifest-path PATH Path to the manifest to document + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never By default the documentation for the local package and all dependencies is built. The output is all placed in `target/doc` in rustdoc's usual format. diff --git a/src/bin/rustc.rs b/src/bin/rustc.rs index 4b7121f43..f1fb15a47 100644 --- a/src/bin/rustc.rs +++ b/src/bin/rustc.rs @@ -29,25 +29,25 @@ pub const USAGE: &'static str = " Compile a package and all of its dependencies Usage: - cargo rustc [options] [-p SPEC --package SPEC]... [--] [...] + cargo rustc [options] [--] [...] Options: - -h, --help Print this message - -p SPEC, --package SPEC The profile to compile for - -j N, --jobs N The number of jobs to run in parallel - --lib Build only this package's library - --bin NAME Build only the specified binary - --example NAME Build only the specified example - --test NAME Build only the specified test target - --bench NAME Build only the specified benchmark target - --release Build artifacts in release mode, with optimizations - --features FEATURES Features to compile for the package - --no-default-features Do not compile default features for the package - --target TRIPLE Target triple which compiles will be for - --manifest-path PATH Path to the manifest to fetch dependencies for - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never + -h, --help Print this message + -p SPEC, --package SPEC ... The profile to compile for + -j N, --jobs N The number of jobs to run in parallel + --lib Build only this package's library + --bin NAME Build only the specified binary + --example NAME Build only the specified example + --test NAME Build only the specified test target + --bench NAME Build only the specified benchmark target + --release Build artifacts in release mode, with optimizations + --features FEATURES Features to compile for the package + --no-default-features Do not compile default features for the package + --target TRIPLE Target triple which compiles will be for + --manifest-path PATH Path to the manifest to fetch dependencies for + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never The specified target for the current package (or package specified by SPEC if provided) will be compiled along with all of its dependencies. The specified diff --git a/src/bin/test.rs b/src/bin/test.rs index 9b89fb912..09981e0be 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -28,27 +28,27 @@ pub const USAGE: &'static str = " Execute all unit and integration tests of a local package Usage: - cargo test [options] [-p SPEC --package SPEC]... [--] [...] + cargo test [options] [--] [...] Options: - -h, --help Print this message - --lib Test only this package's library - --bin NAME Test only the specified binary - --example NAME Test only the specified example - --test NAME Test only the specified integration test target - --bench NAME Test only the specified benchmark target - --no-run Compile, but don't run tests - -p SPEC, --package SPEC Package to run tests for - -j N, --jobs N The number of jobs to run in parallel - --release Build artifacts in release mode, with optimizations - --features FEATURES Space-separated list of features to also build - --no-default-features Do not build the `default` feature - --target TRIPLE Build for the target triple - --manifest-path PATH Path to the manifest to build tests for - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never - --no-fail-fast Run all tests regardless of failure + -h, --help Print this message + --lib Test only this package's library + --bin NAME Test only the specified binary + --example NAME Test only the specified example + --test NAME Test only the specified integration test target + --bench NAME Test only the specified benchmark target + --no-run Compile, but don't run tests + -p SPEC, --package SPEC ... Package to run tests for + -j N, --jobs N The number of jobs to run in parallel + --release Build artifacts in release mode, with optimizations + --features FEATURES Space-separated list of features to also build + --no-default-features Do not build the `default` feature + --target TRIPLE Build for the target triple + --manifest-path PATH Path to the manifest to build tests for + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never + --no-fail-fast Run all tests regardless of failure All of the trailing arguments are passed to the test binaries generated for filtering tests and generally providing options configuring how they run. For diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 1c2ad0705..53167b0d4 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -54,6 +54,7 @@ pub struct TargetConfig { // Returns a mapping of the root package plus its immediate dependencies to // where the compiled libraries are all located. +#[allow(deprecated)] // connect => join in 1.3 pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package, Vec<(&Target, &'a Profile)>)], @@ -66,7 +67,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a [(&Package, -> CargoResult> { debug!("compile_targets: {}", pkg_targets.iter().map(|&(ref p, _)| p.name()) - .collect::>().join(", ")); + .collect::>().connect(", ")); try!(links::validate(deps)); diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 51357eca1..d1b985fa5 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -62,7 +62,10 @@ fn compile_tests<'a>(manifest_path: &Path, options: &TestOptions<'a>) -> CargoResult> { let mut compilation = try!(ops::compile(manifest_path, &options.compile_opts)); - compilation.tests.sort(); + compilation.tests.iter_mut() + .map(|&mut (_, ref mut tests)| + tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2))) + .collect::>(); Ok(compilation) } @@ -76,24 +79,26 @@ fn run_unit_tests(options: &TestOptions, let mut errors = Vec::new(); - for &(_, ref exe) in &compilation.tests { - let to_display = match util::without_prefix(exe, &cwd) { - Some(path) => path, - None => &**exe, - }; - let mut cmd = try!(compilation.target_process(exe, &compilation.package)); - cmd.args(test_args); - try!(config.shell().concise(|shell| { - shell.status("Running", to_display.display().to_string()) - })); - try!(config.shell().verbose(|shell| { - shell.status("Running", cmd.to_string()) - })); + for &(ref pkg, ref tests) in &compilation.tests { + for &(_, ref exe) in tests { + let to_display = match util::without_prefix(exe, &cwd) { + Some(path) => path, + None => &**exe, + }; + let mut cmd = try!(compilation.target_process(exe, pkg)); + cmd.args(test_args); + try!(config.shell().concise(|shell| { + shell.status("Running", to_display.display().to_string()) + })); + try!(config.shell().verbose(|shell| { + shell.status("Running", cmd.to_string()) + })); - if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) { - errors.push(e); - if !options.no_fail_fast { - break + if let Err(e) = ExecEngine::exec(&mut ProcessEngine, cmd) { + errors.push(e); + if !options.no_fail_fast { + break + } } } } @@ -107,15 +112,20 @@ fn run_doc_tests(options: &TestOptions, -> CargoResult> { let mut errors = Vec::new(); let config = options.compile_opts.config; - let libs = compilation.package.targets().iter() - .filter(|t| t.doctested()) - .map(|t| (t.src_path(), t.name(), t.crate_name())); - for (lib, name, crate_name) in libs { + + let mut libs = vec![]; + for package in compilation.to_doc_test.iter() { + libs.extend(package.targets().iter() + .filter(|t| t.doctested()) + .map(|t| (package, t.src_path(), t.name(), t.crate_name()))); + } + + for (package, lib, name, crate_name) in libs { try!(config.shell().status("Doc-tests", name)); - let mut p = try!(compilation.rustdoc_process(&compilation.package)); + let mut p = try!(compilation.rustdoc_process(package)); p.arg("--test").arg(lib) .arg("--crate-name").arg(&crate_name) - .cwd(compilation.package.root()); + .cwd(package.root()); for &rust_dep in &[&compilation.deps_output, &compilation.root_output] { let mut arg = OsString::from("dependency="); @@ -169,44 +179,3 @@ fn run_doc_tests(options: &TestOptions, } Ok(errors) } - -fn build_and_run<'a>(manifest_path: &Path, - options: &TestOptions<'a>, - test_args: &[String]) - -> CargoResult, ProcessError>> { - let config = options.compile_opts.config; - let mut source = try!(PathSource::for_path(&manifest_path.parent().unwrap(), - config)); - try!(source.update()); - - let mut compile = try!(ops::compile(manifest_path, &options.compile_opts)); - if options.no_run { return Ok(Ok(compile)) } - compile.tests.iter_mut() - .map(|&mut (_, ref mut tests)| - tests.sort_by(|&(ref n1, _), &(ref n2, _)| n1.cmp(n2))) - .collect::>(); - - let cwd = config.cwd(); - for &(ref pkg, ref tests) in &compile.tests { - for &(_, ref exe) in tests { - let to_display = match util::without_prefix(exe, &cwd) { - Some(path) => path, - None => &**exe, - }; - let mut cmd = try!(compile.target_process(exe, pkg)); - cmd.args(test_args); - try!(config.shell().concise(|shell| { - shell.status("Running", to_display.display().to_string()) - })); - try!(config.shell().verbose(|shell| { - shell.status("Running", cmd.to_string()) - })); - match ExecEngine::exec(&mut ProcessEngine, cmd) { - Ok(()) => {} - Err(e) => return Ok(Err(e)) - } - } - } - - Ok(Ok(compile)) -} diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 0f7602e99..4411dd625 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -269,7 +269,8 @@ pub struct Execs { expect_stdout: Option, expect_stdin: Option, expect_stderr: Option, - expect_exit_code: Option + expect_exit_code: Option, + expect_stdout_contains: Vec } impl Execs { @@ -289,6 +290,11 @@ impl Execs { self } + pub fn with_stdout_contains(mut self, expected: S) -> Execs { + self.expect_stdout_contains.push(expected.to_string()); + self + } + fn match_output(&self, actual: &Output) -> ham::MatchResult { self.match_status(actual) .and(self.match_stdout(actual)) @@ -312,6 +318,8 @@ impl Execs { fn match_stdout(&self, actual: &Output) -> ham::MatchResult { self.match_std(self.expect_stdout.as_ref(), &actual.stdout, "stdout", &actual.stderr) + .and(self.match_contains(self.expect_stdout_contains.as_ref(), + &actual.stdout, "stdout")) } fn match_stderr(&self, actual: &Output) -> ham::MatchResult { @@ -319,6 +327,40 @@ impl Execs { "stderr", &actual.stdout) } + #[allow(deprecated)] // connect => join in 1.3 + fn match_contains(&self, expect: &[String], actual: &[u8], + description: &str) -> ham::MatchResult { + for s in expect { + let a: Vec<&str> = match str::from_utf8(actual) { + Err(..) => return Err(format!("{} was not utf8 encoded", + description)), + Ok(actual) => actual.lines().collect(), + }; + let e: Vec<&str> = s.lines().collect(); + + let first = e.first().unwrap(); + let mut ai = a.iter(); + match ai.position(|s| lines_match(first, s)) { + Some(_) => { + let match_count = ai.zip(e.iter().skip(1)) + .take_while(|&(a, e)| lines_match(a, e)).count(); + if match_count != (e.len() - 1) { + return ham::expect(false, + format!("expected: {}\n\ + actual: {}", + e.connect("\n"), + a.iter().take(e.len()).map(|&s| s) + .collect::>().connect("\n"))); + } + }, + None => { + return ham::expect(false, format!("no match")); + } + }; + } + ham::expect(true, format!("OK")) + } + #[allow(deprecated)] // connect => join in 1.3 fn match_std(&self, expected: Option<&String>, actual: &[u8], description: &str, extra: &[u8]) -> ham::MatchResult { @@ -446,7 +488,8 @@ pub fn execs() -> Execs { expect_stdout: None, expect_stderr: None, expect_stdin: None, - expect_exit_code: None + expect_exit_code: None, + expect_stdout_contains: vec![] } } diff --git a/tests/test_cargo_bench.rs b/tests/test_cargo_bench.rs index 5e3b21cad..143917258 100644 --- a/tests/test_cargo_bench.rs +++ b/tests/test_cargo_bench.rs @@ -922,3 +922,88 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured ", compiling = COMPILING, running = RUNNING))); }); + +test!(test_bench_multiple_packages { + if !::is_nightly() { return } + + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + authors = [] + version = "0.1.0" + + [dependencies.bar] + path = "../bar" + + [dependencies.baz] + path = "../baz" + "#) + .file("src/lib.rs", ""); + + let bar = project("bar") + .file("Cargo.toml", r#" + [project] + name = "bar" + authors = [] + version = "0.1.0" + + [[bench]] + name = "bbar" + test = true + "#) + .file("src/lib.rs", "") + .file("benches/bbar.rs", r#" + #![feature(test)] + extern crate test; + + use test::Bencher; + + #[bench] + fn bench_bar(_b: &mut Bencher) {} + "#); + bar.build(); + + let baz = project("baz") + .file("Cargo.toml", r#" + [project] + name = "baz" + authors = [] + version = "0.1.0" + + [[bench]] + name = "bbaz" + test = true + "#) + .file("src/lib.rs", "") + .file("benches/bbaz.rs", r#" + #![feature(test)] + extern crate test; + + use test::Bencher; + + #[bench] + fn bench_baz(_b: &mut Bencher) {} + "#); + baz.build(); + + + assert_that(p.cargo_process("bench").arg("-p").arg("bar").arg("-p").arg("baz"), + execs().with_status(0) + .with_stdout_contains(&format!("\ +{running} target[..]release[..]bbaz-[..] + +running 1 test +test bench_baz ... bench: 0 ns/iter (+/- 0) + +test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured +", running = RUNNING)) + .with_stdout_contains(&format!("\ +{running} target[..]release[..]bbar-[..] + +running 1 test +test bench_bar ... bench: 0 ns/iter (+/- 0) + +test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured +", running = RUNNING))); +}); diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index 87e47c2d4..c67e50bb0 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -1927,8 +1927,6 @@ test!(rustc_no_trans { }); test!(build_multiple_packages { - - let p = project("foo") .file("Cargo.toml", r#" [package] @@ -1969,7 +1967,9 @@ test!(build_multiple_packages { .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }"); p.build(); - assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2").arg("-p").arg("foo"), execs()); + assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2") + .arg("-p").arg("foo"), + execs()); assert_that(&p.bin("foo"), existing_file()); assert_that(process(&p.bin("foo")).unwrap(), diff --git a/tests/test_cargo_rustc.rs b/tests/test_cargo_rustc.rs index 800051793..18a09fae1 100644 --- a/tests/test_cargo_rustc.rs +++ b/tests/test_cargo_rustc.rs @@ -1,7 +1,9 @@ use std::path::MAIN_SEPARATOR as SEP; use support::{execs, project}; use support::{COMPILING, RUNNING}; -use hamcrest::{assert_that}; +use hamcrest::{assert_that, existing_file}; +use cargo::util::process; + fn setup() { } @@ -296,3 +298,68 @@ test!(build_only_bar_dependency { compiling = COMPILING, running = RUNNING, url = foo.url()))); }); + +test!(build_multiple_dependencies { + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "../bar" + + [dependencies.baz] + path = "../baz" + "#) + .file("src/main.rs", r#" + fn main() {} + "#); + foo.build(); + let bar = project("bar") + .file("Cargo.toml", r#" + [package] + name = "bar" + version = "0.1.0" + authors = [] + "#) + .file("src/main.rs", r#" + fn main() { + if cfg!(flag = "1") { println!("Yeah from bar!"); } + } + "#); + + bar.build(); + let baz = project("baz") + .file("Cargo.toml", r#" + [package] + name = "baz" + version = "0.1.0" + authors = [] + "#) + .file("src/main.rs", r#" + fn main() { + if cfg!(flag = "1") { println!("Yeah from baz!"); } + } + "#); + baz.build(); + + assert_that(foo.cargo_process("rustc").arg("-v").arg("-p").arg("bar") + .arg("-p").arg("baz").arg("--").arg("--cfg").arg("flag=\"1\""), + execs() + .with_status(0)); + + let bar_bin = &foo.build_dir().join("debug").join("deps").join("bar"); + assert_that(bar_bin, existing_file()); + + assert_that( + process(bar_bin).unwrap(), + execs().with_stdout("Yeah from bar!\n")); + + let baz_bin = &foo.build_dir().join("debug").join("deps").join("baz"); + assert_that(bar_bin, existing_file()); + assert_that( + process(baz_bin).unwrap(), + execs().with_stdout("Yeah from baz!\n")); +}); -- 2.30.2